package com.zch.rpc.core.provider;


import com.zch.rpc.core.exception.RpcException;
import com.zch.rpc.core.model.RpcRequestModel;
import com.zch.rpc.core.model.RpcResponseModel;
import com.zch.rpc.core.net.abstracts.Server;
import com.zch.rpc.core.net.jetty1.JettyServer;
import com.zch.rpc.core.util.IpUtil;
import com.zch.rpc.core.util.NetUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Auther: zch
 * @Date: 2019/1/5 19:53
 * @Description:
 */
public class RpcProviderFactory {
    private static Logger logger = LoggerFactory.getLogger(RpcProviderFactory.class);
    private static ConcurrentHashMap<String, Object> providerMap = new ConcurrentHashMap<>();
    private String protocol;
    private int port;

    public void startServer() throws Exception {
        JettyServer server = new JettyServer();
        server.start(port,null,null);
    }
    public void validConfig(){
        if(NetUtil.isPortUsed(port)){
          throw new RpcException(" rpc port"+ port+"is used");
        }
    }
    public static String makeServiceKey(String interfaceClassName, String groupId, String version) {
        String key = interfaceClassName;
        if (!StringUtils.isEmpty(groupId)) {
            key = key + "#groupId:" + groupId;
        }
        if (!StringUtils.isEmpty(version)) {
            key = key + "#version:" + version;
        }
        return key;
    }

    public void putService(String key, Object bean) {
        providerMap.put(key, bean);
    }

    public static RpcResponseModel invokerService(RpcRequestModel rpcRequestModel) {
        RpcResponseModel responseModel = new RpcResponseModel();
        if(!StringUtils.isEmpty(rpcRequestModel.getMappingUrl())){
            HttpRequestMethodInfo httpRequestMethodInfo= (HttpRequestMethodInfo) getService(rpcRequestModel);
            Object bean=httpRequestMethodInfo.getBean();
            Method method=httpRequestMethodInfo.getMethod();
            Object[] params=rpcRequestModel.getParams();
            try {
                Object result=method.invoke(bean,params);
                responseModel.setData(result);
                return responseModel;
            } catch (Throwable e) {
                logger.error(e.getMessage(),e);
                throw new RpcException(e);
            }
        }else{
            Object bean = getService(rpcRequestModel);
            String methodName=rpcRequestModel.getMethodName();
            Class<?>[] paramsType=rpcRequestModel.getParamTypes();
            Object[] params = rpcRequestModel.getParams();
            try {
                Method method=rpcRequestModel.getInterfaceClass().getMethod(methodName, paramsType);

                Object result = method.invoke(bean, params);
                responseModel.setData(result);
                return responseModel;
            } catch (Throwable e) {
                logger.error(e.getMessage(),e);
                throw new RpcException(e);
            }
        }

    }

    private static Object getService(RpcRequestModel rpcRequestModel) {
        if(!StringUtils.isEmpty(rpcRequestModel.getMappingUrl())){
            return providerMap.get(rpcRequestModel.getMappingUrl());
        }
        Class<?> interfaceClazz = rpcRequestModel.getInterfaceClass();
        String version = rpcRequestModel.getVersion();
        String groupId = rpcRequestModel.getGroupId();
        String key = makeServiceKey(interfaceClazz.getName(), groupId, version);
        Object bean = providerMap.get(key);
        return bean;
    }

    public String getProtocol() {
        return protocol;
    }

    public void setProtocol(String protocol) {
        this.protocol = protocol;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }
}
